GameKit’s
In-Game Voice service lets applications create a walkie-talkie-style
voice channel connecting two devices together. You can use this service
with iPhones, taking advantage of their built-in speaker and
microphone, or with second generation or later iPod touch units by
adding an external microphone. The standard iPhone earbuds with their
built-in mic work very well with iPod touches, routing the audio into
the earbuds and picking up voice input through the microphone.
GameKit as Middleman
To adapt
this code for Voice Chat, you need to think of the GameKit
communications as a voice chat middleman. GameKit handles the data
throughput, both receipt and delivery.
The voice additions, provided by the GKVoiceChatService
class, sit outside normal GameKit. Chat services connect into the
iPhone’s audio playback and recording system, so Voice Chat can listen
to and play back audio. Voice Chat then sends its data through GameKit
and plays back the data it receives from GameKit. Figure 1 shows this separation of responsibilities.
Unfortunately,
you cannot use the GameKit Voice Chat service over a connection other
than Bluetooth. GKVoice expects a GKSession with GKPeers in order to
transmit its data. If you need to use voice transmission for another
connection style, you’ll have to write that layer yourself.
Implementing Voice Chat
When
working with voice, there’s no difference in the way you get started.
You display a peer picker and negotiate the connection, as you would
normally do with GameKit. The difference arrives once the peer
connects. You need to establish the voice chat and redirect the data to
and from that service.
Upon connecting to the new peer, set up the voice chat basics. The peer connection method in Recipe 1
activates a play-and-record audio session, sets the default chat
service client, and starts a new voice chat with that peer. By setting
the client property, you ensure that your class receives the voice chat callbacks needed for negotiating data.
Your primary class must declare the GKVoiceChatClient
protocol to do this. When the chat service gathers data through the
microphone, it triggers the voiceChatService:sendData:toParticipantID:
callback. Here, you can redirect voice data to your normal GameKit
session. For a voice-only connection, just send along the data. When
your application handles both voice and other data, build a dictionary
and tag the data with a key such as @"voice" or When your class receives data through the normal receiveData:fromPeer:inSession:context: callback, the same approaches apply. For voice only, use receivedData:fromParticipantID:
to send the data off to the chat service. Voice Chat allows you to mix
game audio with in-game voice. For voice-data hybrid applications,
deserialize the data, determine whether the packet included voice or
regular data, and redirect that data to the appropriate recipient.
Recipe 1. Adding In-Game Voice Chat Services
- (void)voiceChatService:(GKVoiceChatService *)voiceChatService sendData:(NSData *)data toParticipantID:(NSString *)participantID { // Send the next burst of data to peers [self.session sendData: data toPeers:[NSArray arrayWithObject: participantID] withDataMode: GKSendDataReliable error: nil]; }
- (void) receiveData:(NSData *)data fromPeer:(NSString *)peer inSession: (GKSession *)session context:(void *)context { // Redirect any voice data to the voice chat service [[GKVoiceChatService defaultVoiceChatService] receivedData:data fromParticipantID:peer]; }
- (NSString *)participantID { // provide the session's participant ID for the chat return self.session.peerID; }
- (void)peerPickerController:(GKPeerPickerController *)picker didConnectPeer:(NSString *)peerID toSession: (GKSession *) session{
// Upon connection, close the picker and set the data handler [picker dismiss]; [picker release]; isConnected = YES; [self.session setDataReceiveHandler:self withContext:nil];
// Start the audio session NSError *error; AVAudioSession *audioSession = [AVAudioSession sharedInstance];
if (![audioSession setCategory:AVAudioSessionCategoryPlayAndRecord error:&error]) { NSLog(@"Error setting the AV play/record category: %@", [error localizedDescription]); showAlert(@"Could not establish an Audio Connection. Sorry!"); return; }
if (![audioSession setActive: YES error: &error]) { NSLog(@"Error activating the audio session: %@", [error localizedDescription]); showAlert(@"Could not establish an Audio Connection. Sorry!"); return; }
// Set the voice chat client and start voice chat [GKVoiceChatService defaultVoiceChatService].client = self; if (![[GKVoiceChatService defaultVoiceChatService] startVoiceChatWithParticipantID: peerID error: &error]) { showAlert(@"Could not start voice chat. Sorry!"); NSLog(@"Error starting voice chat"); } }
|